from sympy import (
    S,
    I,
    Abs,
    Eq,
    Reals,
    Function,
    Symbol,
    nonlinsolve,
    simplify,
    solveset,
)
from sympy.core.symbol import _symbol
from sympy.core.relational import Relational, Equality
from sympy.core.expr import Expr
from sympy.core.function import expand
from sympy.core.add import Add
from sympy.calculus.util import continuous_domain
from sympy.solvers.inequalities import solve_univariate_inequality
from sympy.simplify.radsimp import fraction
from sympy.sets.sets import Set, FiniteSet, Union, Interval
from sympy.sets.conditionset import ConditionSet
from sympy.sets.fancysets import ImageSet
from sympy.functions.elementary.complexes import conjugate
from sympy.calculus.util import function_range
from sympy.functions.elementary.integers import floor

import typing as typing


def function_is_odd(f: typing.Union[Expr, Function], x, domain: Set = None) -> bool:
    if not domain:
        domain = continuous_domain(f, x, Reals)
    # check if domain is symmetric
    if isinstance(domain, Union):
        intervals = domain.args
        num = len(intervals)
        for i in range(floor(num / 2) + 1):
            if not (
                Eq(-intervals[i].left, intervals[-i - 1].right)
                and intervals[i].args[2:4] == intervals[-i - 1].args[2:4]
            ):
                return False
    elif isinstance(domain, FiniteSet):
        pass
    elif isinstance(domain, ImageSet):
        pass
    elif isinstance(domain, ConditionSet):
        pass
    elif isinstance(domain, Interval):
        if not (
            Eq(simplify(-domain.inf), simplify(domain.sup))
            and (domain.is_open or domain.is_closed)
        ):
            return False

    # check if the $f(-x)=-f(x)$ is right.
    check = Eq(simplify(f + f.subs(x, -x)), 0)
    if isinstance(check, Equality):
        return solveset(check, x, Reals) == Reals
    else:
        return check
